﻿using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace ExFlash.Actions
{
    public static class ActionAssistant
    {
        public static List<ActionRecord> GetActions(BinaryBitReader reader, int version)
        {
            List<ActionRecord> list = new List<ActionRecord>();

            Byte code = reader.ReadByte();

            while (code != 0)
            {
                ushort recordLength = 0;

                if (code >= 0x80)
                {
                    recordLength = reader.ReadUInt16();
                }

                list.Add(GetActionByCodeAndLength(reader, code, recordLength, version));

                code = reader.ReadByte();
            }

            return list;
        }
        
        public static List<ActionRecord> GetActionsByLength(BinaryBitReader reader, uint totalLength, int version)
        {
            long startIndex = reader.Position;

            List<ActionRecord> list = new List<ActionRecord>();

            while (reader.Position - startIndex < totalLength)
            {
                ushort recordLength = 0;

                Byte code = reader.ReadByte();

                if (code >= 0x80)
                {
                    recordLength = reader.ReadUInt16();                
                }

                list.Add(GetActionByCodeAndLength(reader, code, recordLength, version));
            }

            if (reader.Position - startIndex != totalLength)
            {
                throw new SerializationException("Error while deserializing ActionRecord list - total length doesn't match.");
            }

            return list;
        }

        private static ActionRecord GetActionByCodeAndLength(BinaryBitReader reader, byte code, ushort len, int version)
        {
            ActionRecord rec;

            switch ((ActionCodes)code)
            {
                case ActionCodes.ActionNextFrame:
                    {
                        rec = new ActionNextFrame(len);
                        break;
                    }
                case ActionCodes.ActionPrevFrame:
                    {
                        rec = new ActionPreviousFrame(len);
                        break;
                    }
                case ActionCodes.ActionPlay:
                    {
                        rec = new ActionPlay(len);
                        break;
                    }
                case ActionCodes.ActionStop:
                    {
                        rec = new ActionStop(len);
                        break;
                    }
                case ActionCodes.ActionToggleQuality:
                    {
                        rec = new ActionToggleQuality(len);
                        break;
                    }
                case ActionCodes.ActionStopSounds:
                    {
                        rec = new ActionStopSounds(len);
                        break;
                    }
                case ActionCodes.ActionAdd:
                    {
                        rec = new ActionAdd(len);
                        break;
                    }
                case ActionCodes.ActionSubtract:
                    {
                        rec = new ActionSubtract(len);
                        break;
                    }
                case ActionCodes.ActionMultiply:
                    {
                        rec = new ActionMultiply(len);
                        break;
                    }
                case ActionCodes.ActionDivide:
                    {
                        rec = new ActionDivide(len);
                        break;
                    }
                case ActionCodes.ActionEquals:
                    {
                        rec = new ActionEquals(len);
                        break;
                    }

                case ActionCodes.ActionLess:
                    {
                        rec = new ActionLess(len);
                        break;
                    }
                case ActionCodes.ActionAnd:
                    {
                        rec = new ActionAnd(len);
                        break;
                    }
                case ActionCodes.ActionOr:
                    {
                        rec = new ActionOr(len);
                        break;
                    }
                case ActionCodes.ActionNot:
                    {
                        rec = new ActionNot(len);
                        break;
                    }
                case ActionCodes.ActionStringEquals:
                    {
                        rec = new ActionStringEquals(len);
                        break;
                    }
                case ActionCodes.ActionStringLength:
                    {
                        rec = new ActionStringLength(len);
                        break;
                    }
                case ActionCodes.ActionStringExtract:
                    {
                        rec = new ActionStringExtract(len);
                        break;
                    }
                case ActionCodes.ActionPop:
                    {
                        rec = new ActionPop(len);
                        break;
                    }
                case ActionCodes.ActionToInteger:
                    {
                        rec = new ActionToInteger(len);
                        break;
                    }
                case ActionCodes.ActionGetVariable:
                    {
                        rec = new ActionGetVariable(len);
                        break;
                    }
                case ActionCodes.ActionSetVariable:
                    {
                        rec = new ActionSetVariable(len);
                        break;
                    }
                case ActionCodes.ActionSetTarget2:
                    {
                        rec = new ActionSetTarget2(len);
                        break;
                    }
                case ActionCodes.ActionStringAdd:
                    {
                        rec = new ActionStringAdd(len);
                        break;
                    }
                case ActionCodes.ActionGetProperty:
                    {
                        rec = new ActionGetProperty(len);
                        break;
                    }
                case ActionCodes.ActionSetProperty:
                    {
                        rec = new ActionSetProperty(len);
                        break;
                    }
                case ActionCodes.ActionCloneSprite:
                    {
                        rec = new ActionCloneSprite(len);
                        break;
                    }
                case ActionCodes.ActionRemoveSprite:
                    {
                        rec = new ActionRemoveSprite(len);
                        break;
                    }
                case ActionCodes.ActionTrace:
                    {
                        rec = new ActionTrace(len);
                        break;
                    }
                case ActionCodes.ActionStartDrag:
                    {
                        rec = new ActionStartDrag(len);
                        break;
                    }
                case ActionCodes.ActionEndDrag:
                    {
                        rec = new ActionEndDrag(len);
                        break;
                    }
                case ActionCodes.ActionStringLess:
                    {
                        rec = new ActionStringLess(len);
                        break;
                    }
                case ActionCodes.ActionThrow:
                    {
                        rec = new ActionThrow(len);
                        break;
                    }
                case ActionCodes.ActionCastOp:
                    {
                        rec = new ActionCastOp(len);
                        break;
                    }
                case ActionCodes.ActionImplementsOp:
                    {
                        rec = new ActionImplementsOp(len);
                        break;
                    }
                case ActionCodes.ActionRandomNumber:
                    {
                        rec = new ActionRandomNumber(len);
                        break;
                    }
                case ActionCodes.ActionMbStringLength:
                    {
                        rec = new ActionMbStringLength(len);
                        break;
                    }
                case ActionCodes.ActionCharToAscii:
                    {
                        rec = new ActionCharToAscii(len);
                        break;
                    }
                case ActionCodes.ActionAsciiToChar:
                    {
                        rec = new ActionAsciiToChar(len);
                        break;
                    }
                case ActionCodes.ActionGetTime:
                    {
                        rec = new ActionGetTime(len);
                        break;
                    }
                case ActionCodes.ActionMbStringExtract:
                    {
                        rec = new ActionMbStringExtract(len);
                        break;
                    }
                case ActionCodes.ActionMbCharToAscii:
                    {
                        rec = new ActionMbCharToAscii(len);
                        break;
                    }
                case ActionCodes.ActionMbAsciiToChar:
                    {
                        rec = new ActionMbAsciiToChar(len);
                        break;
                    }
                case ActionCodes.ActionDelete:
                    {
                        rec = new ActionDelete(len);
                        break;
                    }
                case ActionCodes.ActionDelete2:
                    {
                        rec = new ActionDelete2(len);
                        break;
                    }
                case ActionCodes.ActionDefineLocal:
                    {
                        rec = new ActionDefineLocal(len);
                        break;
                    }
                case ActionCodes.ActionCallFunction:
                    {
                        rec = new ActionCallFunction(len);
                        break;
                    }
                case ActionCodes.ActionReturn:
                    {
                        rec = new ActionReturn(len);
                        break;
                    }
                case ActionCodes.ActionModulo:
                    {
                        rec = new ActionModulo(len);
                        break;
                    }
                case ActionCodes.ActionNewObject:
                    {
                        rec = new ActionNewObject(len);
                        break;
                    }
                case ActionCodes.ActionDefineLocal2:
                    {
                        rec = new ActionDefineLocal2(len);
                        break;
                    }
                case ActionCodes.ActionInitArray:
                    {
                        rec = new ActionInitArray(len);
                        break;
                    }
                case ActionCodes.ActionInitObject:
                    {
                        rec = new ActionInitObject(len);
                        break;
                    }
                case ActionCodes.ActionTypeOf:
                    {
                        rec = new ActionTypeOf(len);
                        break;
                    }
                case ActionCodes.ActionTargetPath:
                    {
                        rec = new ActionTargetPath(len);
                        break;
                    }
                case ActionCodes.ActionEnumerate:
                    {
                        rec = new ActionEnumerate(len);
                        break;
                    }
                case ActionCodes.ActionAdd2:
                    {
                        rec = new ActionAdd2(len);
                        break;
                    }
                case ActionCodes.ActionLess2:
                    {
                        rec = new ActionLess2(len);
                        break;
                    }
                case ActionCodes.ActionEquals2:
                    {
                        rec = new ActionEquals2(len);
                        break;
                    }
                case ActionCodes.ActionToNumber:
                    {
                        rec = new ActionToNumber(len);
                        break;
                    }
                case ActionCodes.ActionToString:
                    {
                        rec = new ActionToString(len);
                        break;
                    }
                case ActionCodes.ActionPushDuplicate:
                    {
                        rec = new ActionPushDuplicate(len);
                        break;
                    }
                case ActionCodes.ActionStackSwap:
                    {
                        rec = new ActionStackSwap(len);
                        break;
                    }
                case ActionCodes.ActionGetMember:
                    {
                        rec = new ActionGetMember(len);
                        break;
                    }
                case ActionCodes.ActionSetMember:
                    {
                        rec = new ActionSetMember(len);
                        break;
                    }
                case ActionCodes.ActionIncrement:
                    {
                        rec = new ActionIncrement(len);
                        break;
                    }
                case ActionCodes.ActionDecrement:
                    {
                        rec = new ActionDecrement(len);
                        break;
                    }
                case ActionCodes.ActionCallMethod:
                    {
                        rec = new ActionCallMethod(len);
                        break;
                    }
                case ActionCodes.ActionNewMethod:
                    {
                        rec = new ActionNewMethod(len);
                        break;
                    }
                case ActionCodes.ActionInstanceOf:
                    {
                        rec = new ActionInstanceOf(len);
                        break;
                    }
                case ActionCodes.ActionEnumerate2:
                    {
                        rec = new ActionEnumerate2(len);
                        break;
                    }
                case ActionCodes.ActionBitAnd:
                    {
                        rec = new ActionBitAnd(len);
                        break;
                    }
                case ActionCodes.ActionBitOr:
                    {
                        rec = new ActionBitOr(len);
                        break;
                    }
                case ActionCodes.ActionBitXor:
                    {
                        rec = new ActionBitXor(len);
                        break;
                    }
                case ActionCodes.ActionBitLshift:
                    {
                        rec = new ActionBitLshift(len);
                        break;
                    }
                case ActionCodes.ActionBitRshift:
                    {
                        rec = new ActionBitRshift(len);
                        break;
                    }
                case ActionCodes.ActionBitURShift:
                    {
                        rec = new ActionBitURShift(len);
                        break;
                    }
                case ActionCodes.ActionStrictEquals:
                    {
                        rec = new ActionStrictEquals(len);
                        break;
                    }
                case ActionCodes.ActionGreater:
                    {
                        rec = new ActionGreater(len);
                        break;
                    }
                case ActionCodes.ActionStringGreater:
                    {
                        rec = new ActionStringGreater(len);
                        break;
                    }
                case ActionCodes.ActionExtends:
                    {
                        rec = new ActionExtends(len);
                        break;
                    }
                case ActionCodes.ActionGoToFrame:
                    {
                        rec = new ActionGoToFrame(len);
                        break;
                    }
                case ActionCodes.ActionGetUrl:
                    {
                        rec = new ActionGetUrl(len, version);
                        break;
                    }
                case ActionCodes.ActionStoreRegister:
                    {
                        rec = new ActionStoreRegister(len);
                        break;
                    }
                case ActionCodes.ActionConstantPool:
                    {
                        rec = new ActionConstantPool(len, version);
                        break;
                    }
                case ActionCodes.ActionWaitForFrame:
                    {
                        rec = new ActionWaitForFrame(len);
                        break;
                    }
                case ActionCodes.ActionSetTarget:
                    {
                        rec = new ActionSetTarget(len, version);
                        break;
                    }
                case ActionCodes.ActionGoToLabel:
                    {
                        rec = new ActionGoToLabel(len, version);
                        break;
                    }
                case ActionCodes.ActionWaitForFrame2:
                    {
                        rec = new ActionWaitForFrame2(len);
                        break;
                    }
                case ActionCodes.ActionDefineFunction2:
                    {
                        rec = new ActionDefineFunction2(len, version);
                        break;
                    }
                case ActionCodes.ActionTry:
                    {
                        rec = new ActionTry(len, version);
                        break;
                    }
                case ActionCodes.ActionWith:
                    {
                        rec = new ActionWith(len);
                        break;
                    }
                case ActionCodes.ActionPush:
                    {
                        rec = new ActionPush(len, version);
                        break;
                    }
                case ActionCodes.ActionJump:
                    {
                        rec = new ActionJump(len);
                        break;
                    }
                case ActionCodes.ActionGetUrl2:
                    {
                        rec = new ActionGetUrl2(len);
                        break;
                    }
                case ActionCodes.ActionDefineFunction:
                    {
                        rec = new ActionDefineFunction(len, version);
                        break;
                    }
                case ActionCodes.ActionIf:
                    {
                        rec = new ActionIf(len);
                        break;
                    }
                case ActionCodes.ActionCall:
                    {
                        rec = new ActionCall(len);
                        break;
                    }
                case ActionCodes.ActionGoToFrame2:
                    {
                        rec = new ActionGoToFrame2(len);
                        break;
                    }
                default:
                    {
                        rec = new UnknownAction(code,len);
                        break;
                    }
            }

            rec.SwfDeserialize(reader);

            return rec;
        }
    }
}
